EDI

Kimi.Huang 6 years ago
parent
commit
b50be74919

+ 12 - 0
api/stock_views.py

@@ -0,0 +1,12 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from __future__ import division
4
+
5
+from django.shortcuts import HttpResponse
6
+
7
+from utils.stock_utils import refresh_stock_info
8
+
9
+
10
+def refresh_stockinfo(request):
11
+    refresh_stock_info()
12
+    return HttpResponse('Refresh Success')

+ 5 - 1
api/urls.py

@@ -2,7 +2,7 @@
2 2
 
3 3
 from django.conf.urls import url
4 4
 
5
-from api import oauth_views
5
+from api import oauth_views, stock_views
6 6
 
7 7
 
8 8
 urlpatterns = [
@@ -12,3 +12,7 @@ urlpatterns += [
12 12
     url(r'^3rd/or$', oauth_views.oauth_redirect, name='3rd_or'),
13 13
     url(r'^3rd/oauth_redirect$', oauth_views.oauth_redirect, name='3rd_oauth_redirect'),
14 14
 ]
15
+
16
+urlpatterns = [
17
+    url(r'^refresh$', stock_views.refresh_stockinfo, name='refresh_stockinfo'),
18
+]

+ 17 - 0
jd/__init__.py

@@ -0,0 +1,17 @@
1
+from jd.api.base import sign
2
+
3
+
4
+class appinfo(object):
5
+    def __init__(self, appkey, secret):
6
+        self.appkey = appkey
7
+        self.secret = secret
8
+
9
+
10
+def getDefaultAppInfo():
11
+    pass
12
+
13
+
14
+def setDefaultAppInfo(appkey, secret):
15
+    default = appinfo(appkey, secret)
16
+    global getDefaultAppInfo
17
+    getDefaultAppInfo = lambda: default

+ 7 - 0
jd/admin.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.contrib import admin
5
+
6
+
7
+# Register your models here.

+ 2 - 0
jd/api/__init__.py

@@ -0,0 +1,2 @@
1
+from jd.api.rest import *
2
+from jd.api.base import FileItem

+ 235 - 0
jd/api/base.py

@@ -0,0 +1,235 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+try:
4
+    import httplib
5
+except ImportError:
6
+    import http.client as httplib
7
+import hashlib
8
+import itertools
9
+import json
10
+import mimetypes
11
+import time
12
+import urllib
13
+
14
+from CodeConvert import CodeConvert as cc
15
+
16
+import jd
17
+
18
+
19
+'''
20
+定义一些系统变量
21
+'''
22
+
23
+P_APPKEY = "app_key"
24
+P_API = "method"
25
+P_ACCESS_TOKEN = "access_token"
26
+P_VERSION = "v"
27
+P_FORMAT = "format"
28
+P_TIMESTAMP = "timestamp"
29
+P_SIGN = "sign"
30
+P_JSON_PARAM_KEY = "360buy_param_json"
31
+
32
+P_CODE = 'code'
33
+P_SUB_CODE = 'sub_code'
34
+P_MSG = 'msg'
35
+P_SUB_MSG = 'sub_msg'
36
+
37
+
38
+N_REST = '/routerjson'
39
+
40
+
41
+def sign(secret, parameters):
42
+    # ===========================================================================
43
+    # '''签名方法
44
+    # @param secret: 签名需要的密钥
45
+    # @param parameters: 支持字典和string两种
46
+    # '''
47
+    # ===========================================================================
48
+    # 如果parameters 是字典类的话
49
+    if hasattr(parameters, "items"):
50
+        keys = parameters.keys()
51
+        keys.sort()
52
+
53
+        parameters = "%s%s%s" % (secret, str().join('%s%s' % (key, parameters[key]) for key in keys), secret)
54
+    return hashlib.md5(parameters).hexdigest().upper()
55
+
56
+
57
+def mixStr(pstr):
58
+    if isinstance(pstr, str):
59
+        return pstr
60
+    elif isinstance(pstr, unicode):
61
+        return pstr.encode('utf-8')
62
+    else:
63
+        return str(pstr)
64
+
65
+
66
+class FileItem(object):
67
+    def __init__(self, filename=None, content=None):
68
+        self.filename = filename
69
+        self.content = content
70
+
71
+
72
+class MultiPartForm(object):
73
+    """Accumulate the data to be used when posting a form."""
74
+
75
+    def __init__(self):
76
+        self.form_fields = []
77
+        self.files = []
78
+        self.boundary = "PYTHON_SDK_BOUNDARY"
79
+        return
80
+
81
+    def get_content_type(self):
82
+        return 'multipart/form-data; boundary=%s' % self.boundary
83
+
84
+    def add_field(self, name, value):
85
+        """Add a simple field to the form data."""
86
+        self.form_fields.append((name, str(value)))
87
+        return
88
+
89
+    def add_file(self, fieldname, filename, fileHandle, mimetype=None):
90
+        """Add a file to be uploaded."""
91
+        body = fileHandle.read()
92
+        if mimetype is None:
93
+            mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
94
+        self.files.append((mixStr(fieldname), mixStr(filename), mixStr(mimetype), mixStr(body)))
95
+        return
96
+
97
+    def __str__(self):
98
+        """Return a string representing the form data, including attached files."""
99
+        # Build a list of lists, each containing "lines" of the
100
+        # request.  Each part is separated by a boundary string.
101
+        # Once the list is built, return a string where each
102
+        # line is separated by '\r\n'.
103
+        parts = []
104
+        part_boundary = '--' + self.boundary
105
+
106
+        # Add the form fields
107
+        parts.extend([part_boundary, 'Content-Disposition: form-data; name="%s"' % name, 'Content-Type: text/plain; charset=UTF-8', '', value] for name, value in self.form_fields)
108
+
109
+        # Add the files to upload
110
+        parts.extend([part_boundary, 'Content-Disposition: file; name="%s"; filename="%s"' % (field_name, filename), 'Content-Type: %s' % content_type, 'Content-Transfer-Encoding: binary', '', body] for field_name, filename, content_type, body in self.files)
111
+
112
+        # Flatten the list and add closing boundary marker,
113
+        # then return CR+LF separated data
114
+        flattened = list(itertools.chain(*parts))
115
+        flattened.append('--' + self.boundary + '--')
116
+        flattened.append('')
117
+        return '\r\n'.join(flattened)
118
+
119
+
120
+class JdException(Exception):
121
+    # ===========================================================================
122
+    # 业务异常类
123
+    # ===========================================================================
124
+    def __init__(self):
125
+        self.errorcode = None
126
+        self.message = None
127
+        self.subcode = None
128
+        self.submsg = None
129
+        self.application_host = None
130
+        self.service_host = None
131
+
132
+    def __str__(self, *args, **kwargs):
133
+        sb = "errorcode=" + mixStr(self.errorcode) +\
134
+            " message=" + mixStr(self.message) +\
135
+            " subcode=" + mixStr(self.subcode) +\
136
+            " submsg=" + mixStr(self.submsg) +\
137
+            " application_host=" + mixStr(self.application_host) +\
138
+            " service_host=" + mixStr(self.service_host)
139
+        return sb
140
+
141
+
142
+class RequestException(Exception):
143
+    # ===========================================================================
144
+    # 请求连接异常类
145
+    # ===========================================================================
146
+    pass
147
+
148
+
149
+class RestApi(object):
150
+    # ===========================================================================
151
+    # Rest api的基类
152
+    # ===========================================================================
153
+
154
+    def __init__(self, domain='gw.api.360buy.net', port=80):
155
+        # =======================================================================
156
+        # 初始化基类
157
+        # Args @param domain: 请求的域名或者ip
158
+        #      @param port: 请求的端口
159
+        # =======================================================================
160
+        self.__domain = domain
161
+        self.__port = port
162
+        self.__httpmethod = "POST"
163
+        if jd.getDefaultAppInfo():
164
+            self.__app_key = jd.getDefaultAppInfo().appkey
165
+            self.__secret = jd.getDefaultAppInfo().secret
166
+
167
+    def get_request_header(self):
168
+        return {
169
+            'Content-type': 'application/x-www-form-urlencoded',
170
+            "Cache-Control": "no-cache",
171
+            "Connection": "Keep-Alive",
172
+        }
173
+
174
+    def set_app_info(self, appinfo):
175
+        # =======================================================================
176
+        # 设置请求的app信息
177
+        # @param appinfo: import jd
178
+        #                 appinfo jd.appinfo(appkey,secret)
179
+        # =======================================================================
180
+        self.__app_key = appinfo.appkey
181
+        self.__secret = appinfo.secret
182
+
183
+    def getapiname(self):
184
+        return ""
185
+
186
+    def getMultipartParas(self):
187
+        return []
188
+
189
+    def getTranslateParas(self):
190
+        return {}
191
+
192
+    def _check_requst(self):
193
+        pass
194
+
195
+    def getResponse(self, accessToken=None, timeout=30):
196
+        # =======================================================================
197
+        # 获取response结果
198
+        # =======================================================================
199
+        connection = httplib.HTTPConnection(self.__domain, self.__port, timeout)
200
+        sys_parameters = {
201
+            P_APPKEY: self.__app_key,
202
+            P_VERSION: '2.0',
203
+            P_API: self.getapiname(),
204
+            P_TIMESTAMP: time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
205
+        }
206
+        if accessToken is not None:
207
+            sys_parameters[P_ACCESS_TOKEN] = accessToken
208
+        application_parameter = self.getApplicationParameters()
209
+        application_parameter = cc.Convert2Utf8(application_parameter)
210
+        sys_parameters[P_JSON_PARAM_KEY] = json.dumps(application_parameter, ensure_ascii=False, separators=(',', ':'))
211
+        sys_parameters[P_SIGN] = sign(self.__secret, sys_parameters)
212
+        connection.connect()
213
+        url = "http://" + self.__domain + N_REST + "?" + urllib.urlencode(sys_parameters)
214
+        print url
215
+        connection.request(self.__httpmethod, url)
216
+        response = connection.getresponse()
217
+        result = response.read()
218
+        jsonobj = json.loads(result)
219
+        return jsonobj
220
+
221
+    def getApplicationParameters(self):
222
+        application_parameter = {}
223
+        for key, value in self.__dict__.iteritems():
224
+            if not key.startswith("__") and key not in self.getMultipartParas() and not key.startswith("_RestApi__") and value is not None:
225
+                if key.startswith("_"):
226
+                    application_parameter[key[1:]] = value
227
+                else:
228
+                    application_parameter[key] = value
229
+        # 查询翻译字典来规避一些关键字属性
230
+        translate_parameter = self.getTranslateParas()
231
+        for key, value in application_parameter.iteritems():
232
+            if key in translate_parameter:
233
+                application_parameter[translate_parameter[key]] = application_parameter[key]
234
+                del application_parameter[key]
235
+        return application_parameter

+ 21 - 0
jd/api/rest/EdiInventorySendRequest.py

@@ -0,0 +1,21 @@
1
+from jd.api.base import RestApi
2
+
3
+
4
+class EdiInventorySendRequest(RestApi):
5
+    def __init__(self, domain='gw.api.360buy.com', port=80):
6
+        RestApi.__init__(self, domain, port)
7
+        self.vendorCode = None
8
+        self.vendorName = None
9
+        self.vendorProductId = None
10
+        self.inventoryDate = None
11
+        self.totalQuantity = None
12
+        self.estimateDate = None
13
+        self.totalEstimateQuantity = None
14
+        self.costPrice = None
15
+        self.storeId = None
16
+        self.storeName = None
17
+        self.quantity = None
18
+        self.estimateQuantity = None
19
+
20
+    def getapiname(self):
21
+        return 'jingdong.edi.inventory.send'

+ 10 - 0
jd/api/rest/PopVenderCenerVenderBrandQueryRequest.py

@@ -0,0 +1,10 @@
1
+from jd.api.base import RestApi
2
+
3
+
4
+class PopVenderCenerVenderBrandQueryRequest(RestApi):
5
+    def __init__(self, domain='gw.api.360buy.com', port=80):
6
+        RestApi.__init__(self, domain, port)
7
+        self.name = None
8
+
9
+    def getapiname(self):
10
+        return 'jingdong.pop.vender.cener.venderBrand.query'

+ 9 - 0
jd/api/rest/UserCategory3InfoGetRequest.py

@@ -0,0 +1,9 @@
1
+from jd.api.base import RestApi
2
+
3
+
4
+class UserCategory3InfoGetRequest(RestApi):
5
+    def __init__(self, domain='gw.api.360buy.com', port=80):
6
+        RestApi.__init__(self, domain, port)
7
+
8
+    def getapiname(self):
9
+        return 'jingdong.userCategory3.info.get'

+ 11 - 0
jd/api/rest/VcAplsStockBatchGetProdStockInfoRequest.py

@@ -0,0 +1,11 @@
1
+from jd.api.base import RestApi
2
+
3
+
4
+class VcAplsStockBatchGetProdStockInfoRequest(RestApi):
5
+    def __init__(self, domain='gw.api.360buy.com', port=80):
6
+        RestApi.__init__(self, domain, port)
7
+        self.vendorCode = None
8
+        self.skuList = None
9
+
10
+    def getapiname(self):
11
+        return 'jingdong.vc.apls.stock.batchGetProdStockInfo'

+ 14 - 0
jd/api/rest/VcAplsStockUpdateProdStockInfoRequest.py

@@ -0,0 +1,14 @@
1
+from jd.api.base import RestApi
2
+
3
+
4
+class VcAplsStockUpdateProdStockInfoRequest(RestApi):
5
+    def __init__(self, domain='gw.api.360buy.com', port=80):
6
+        RestApi.__init__(self, domain, port)
7
+        self.vendorCode = None
8
+        self.companyId = None
9
+        self.stockRfId = None
10
+        self.skuid = None
11
+        self.stockNum = None
12
+
13
+    def getapiname(self):
14
+        return 'jingdong.vc.apls.stock.updateProdStockInfo'

+ 10 - 0
jd/api/rest/VcItemProductGetRequest.py

@@ -0,0 +1,10 @@
1
+from jd.api.base import RestApi
2
+
3
+
4
+class VcItemProductGetRequest(RestApi):
5
+    def __init__(self, domain='gw.api.360buy.com', port=80):
6
+        RestApi.__init__(self, domain, port)
7
+        self.wareId = None
8
+
9
+    def getapiname(self):
10
+        return 'jingdong.vc.item.product.get'

+ 18 - 0
jd/api/rest/VcItemProductsFindRequest.py

@@ -0,0 +1,18 @@
1
+from jd.api.base import RestApi
2
+
3
+
4
+class VcItemProductsFindRequest(RestApi):
5
+    def __init__(self, domain='gw.api.360buy.com', port=80):
6
+        RestApi.__init__(self, domain, port)
7
+        self.ware_id = None
8
+        self.name = None
9
+        self.brand_id = None
10
+        self.category_id = None
11
+        self.sale_state = None
12
+        self.begin_modify_time = None
13
+        self.end_modify_time = None
14
+        self.offset = None
15
+        self.page_size = None
16
+
17
+    def getapiname(self):
18
+        return 'jingdong.vc.item.products.find'

+ 0 - 0
jd/api/rest/__init__.py


+ 8 - 0
jd/apps.py

@@ -0,0 +1,8 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.apps import AppConfig
5
+
6
+
7
+class JdConfig(AppConfig):
8
+    name = 'jd'

+ 0 - 0
jd/migrations/__init__.py


+ 7 - 0
jd/models.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models
5
+
6
+
7
+# Create your models here.

+ 7 - 0
jd/tests.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.test import TestCase
5
+
6
+
7
+# Create your tests here.

+ 7 - 0
jd/views.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.shortcuts import render
5
+
6
+
7
+# Create your views here.

+ 19 - 0
jdjos/settings.py

@@ -55,6 +55,9 @@ INSTALLED_APPS = [
55 55
     'django_we',
56 56
     'commands',
57 57
     'api',
58
+    'jd',
59
+    'jos',
60
+    'stock',
58 61
 ]
59 62
 
60 63
 MIDDLEWARE = [
@@ -298,6 +301,7 @@ DJANGO_SHORT_URL_REDIRECT_URL = ''
298 301
 
299 302
 # Django-We Settings
300 303
 DJANGO_WE_QUOTE_OR_NOT = True
304
+DJANGO_WE_MODEL_DISPLAY_OR_NOT = False
301 305
 # Enable Cookie or not
302 306
 # DJANGO_WE_BASE_REDIRECT_SET_COOKIE = False
303 307
 # DJANGO_WE_USERINFO_REDIRECT_SET_COOKIE = True
@@ -305,6 +309,20 @@ DJANGO_WE_QUOTE_OR_NOT = True
305 309
 DJANGO_WE_COOKIE_MAX_AGE = COOKIE_MAX_AGE
306 310
 DJANGO_WE_COOKIE_SALT = COOKIE_SALT
307 311
 
312
+
313
+JOS = {
314
+    'TAMRON': {
315
+        'appkey': '',
316
+        'secret': '',
317
+        'accessToken': '',
318
+        'vendorCode': '',
319
+        'vendorName': '',
320
+        'storeId': '',
321
+        'storeName': '',
322
+    }
323
+}
324
+JOS_SKU_EXCLUDE = [1, 2, 3]
325
+
308 326
 # 开发调试相关配置
309 327
 if DEBUG:
310 328
     try:
@@ -342,6 +360,7 @@ WECHAT_DIRECT_USERINFO_REDIRECT_URI = '{0}/we/direct_userinfo_redirect'.format(D
342 360
 
343 361
 JDJOS_OAUTH_AUTHORIZE = 'https://oauth.jd.com/oauth/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&state={state}'
344 362
 JDJOS_OAUTH_TOKEN = 'https://oauth.jd.com/oauth/token?grant_type=authorization_code&client_id={client_id}&redirect_uri={redirect_uri}&code={code}&state={state}&client_secret={client_secret}'
363
+
345 364
 JDJOS_REDIRECT_URI = '{0}/jos/oauth'.format(DOMAIN)
346 365
 
347 366
 # Redis 连接

+ 6 - 2
jdjos/urls.py

@@ -44,9 +44,13 @@ urlpatterns += [
44 44
     # url(r'^page/', include('page.urls', namespace='page')),
45 45
 ]
46 46
 
47
+urlpatterns += [
48
+    url(r'^jos/', include('jos.urls', namespace='jos')),
49
+]
50
+
47 51
 urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
48 52
 urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
49 53
 
50 54
 # AdminSite
51
-admin.site.site_title = ''
52
-admin.site.site_header = 'My administration'
55
+admin.site.site_title = '[腾龙]京东EDI管理系统'
56
+admin.site.site_header = '[腾龙]京东EDI管理系统'

+ 0 - 0
jos/__init__.py


+ 7 - 0
jos/admin.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.contrib import admin
5
+
6
+
7
+# Register your models here.

+ 8 - 0
jos/apps.py

@@ -0,0 +1,8 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.apps import AppConfig
5
+
6
+
7
+class JosConfig(AppConfig):
8
+    name = 'jos'

+ 10 - 0
jos/jos_views.py

@@ -0,0 +1,10 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from __future__ import division
4
+
5
+from django.conf import settings
6
+from django.shortcuts import redirect
7
+
8
+
9
+def redirect_func(request):
10
+    return redirect('{}/admin'.format(settings.DOMAIN))

+ 0 - 0
jos/migrations/__init__.py


+ 7 - 0
jos/models.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models
5
+
6
+
7
+# Create your models here.

+ 7 - 0
jos/tests.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.test import TestCase
5
+
6
+
7
+# Create your tests here.

+ 10 - 0
jos/urls.py

@@ -0,0 +1,10 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.conf.urls import url
4
+
5
+from jos import jos_views
6
+
7
+
8
+urlpatterns = [
9
+    url(r'^$', jos_views.redirect_func, name='redirect_func'),
10
+]

+ 7 - 0
jos/views.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.shortcuts import render
5
+
6
+
7
+# Create your views here.

+ 2 - 1
pep8.sh

@@ -6,5 +6,6 @@
6 6
 #  -- E128 continuation line under-indented for visual indent
7 7
 #  -- E402 module level import not at top of file
8 8
 #  -- E501 line too long
9
+#  -- E731 do not assign a lambda expression, use a def
9 10
 
10
-pycodestyle --exclude=build,migrations,.tox --ignore=E128,E402,E501 .
11
+pycodestyle --exclude=build,migrations,.tox --ignore=E128,E402,E501,E731 .

+ 1 - 1
requirements_dj.txt

@@ -1,4 +1,4 @@
1
-Django==1.11.16
1
+Django==1.11.20
2 2
 django-admin==1.3.2
3 3
 django-detect==1.0.8
4 4
 django-file==1.0.3

+ 0 - 0
stock/__init__.py


+ 21 - 0
stock/admin.py

@@ -0,0 +1,21 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib import admin
4
+from django_admin import AdvancedExportExcelModelAdmin, ReadOnlyModelAdmin
5
+
6
+from stock.models import StockInfo
7
+from utils.stock_utils import update_stock_info
8
+
9
+
10
+class StockInfoAdmin(AdvancedExportExcelModelAdmin, admin.ModelAdmin):
11
+    # list_display = ('stock_id', 'vendorCode', 'vendorName', 'vendorProductId', 'vendorProductName', 'storeId', 'storeName', 'quantity', 'estimateQuantity', 'inventoryDate', 'totalQuantity', 'estimateDate', 'totalEstimateQuantity', 'costPrice', 'status', 'created_at', 'updated_at')
12
+    list_display = ('vendorProductId', 'vendorProductName', 'inventoryDate', 'totalQuantity', 'estimateDate', 'totalEstimateQuantity', 'costPrice', 'updated_at')
13
+    readonly_fields = ('stock_id', 'vendorCode', 'vendorName', 'vendorProductId', 'vendorProductName', 'storeId', 'storeName', 'quantity', 'estimateQuantity', 'status')
14
+
15
+    def save_model(self, request, obj, form, change):
16
+        obj.save()
17
+        if obj.inventoryDate and obj.estimateDate:
18
+            update_stock_info(obj)
19
+
20
+
21
+admin.site.register(StockInfo, StockInfoAdmin)

+ 8 - 0
stock/apps.py

@@ -0,0 +1,8 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.apps import AppConfig
5
+
6
+
7
+class StockConfig(AppConfig):
8
+    name = 'stock'

+ 43 - 0
stock/migrations/0001_initial.py

@@ -0,0 +1,43 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.20 on 2019-03-03 21:40
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations, models
6
+import shortuuidfield.fields
7
+
8
+
9
+class Migration(migrations.Migration):
10
+
11
+    initial = True
12
+
13
+    dependencies = [
14
+    ]
15
+
16
+    operations = [
17
+        migrations.CreateModel(
18
+            name='StockInfo',
19
+            fields=[
20
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21
+                ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')),
22
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')),
23
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')),
24
+                ('stock_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='Stock\u552f\u4e00\u6807\u8bc6', max_length=22, null=True)),
25
+                ('vendorCode', models.CharField(blank=True, help_text='\u4f9b\u5e94\u5546\u7b80\u7801', max_length=8, null=True, verbose_name='vendorCode')),
26
+                ('vendorName', models.CharField(blank=True, help_text='\u4f9b\u5e94\u5546\u540d\u79f0', max_length=32, null=True, verbose_name='vendorName')),
27
+                ('vendorProductId', models.CharField(blank=True, db_index=True, help_text='\u4f9b\u5e94\u5546\u5546\u54c1ID', max_length=32, null=True, verbose_name='vendorProductId')),
28
+                ('storeId', models.CharField(blank=True, help_text='\u4f9b\u5e94\u5546\u4ed3\u5e93ID', max_length=8, null=True, verbose_name='storeId')),
29
+                ('storeName', models.CharField(blank=True, help_text='\u4f9b\u5e94\u5546\u4ed3\u5e93\u540d\u79f0', max_length=32, null=True, verbose_name='storeName')),
30
+                ('quantity', models.IntegerField(default=0, help_text='\u5206\u4ed3\u5e93\u5b58\u6570\u91cf', verbose_name='quantity')),
31
+                ('estimateQuantity', models.IntegerField(default=0, help_text='\u9884\u8ba1\u5e93\u5b58\u6570\u91cf', verbose_name='estimateQuantity')),
32
+                ('inventoryDate', models.DateTimeField(blank=True, help_text='\u5e93\u5b58\u65e5\u671f', null=True, verbose_name='inventoryDate')),
33
+                ('totalQuantity', models.IntegerField(default=0, help_text='\u5e93\u5b58\u603b\u91cf', verbose_name='totalQuantity')),
34
+                ('estimateDate', models.DateTimeField(blank=True, help_text='\u9884\u8ba1\u5e93\u5b58\u65e5\u671f', null=True, verbose_name='estimateDate')),
35
+                ('totalEstimateQuantity', models.IntegerField(default=0, help_text='\u9884\u8ba1\u5e93\u5b58\u603b\u91cf', verbose_name='totalEstimateQuantity')),
36
+                ('costPrice', models.IntegerField(default=0, help_text='\u8fdb\u4ef7', verbose_name='costPrice')),
37
+            ],
38
+            options={
39
+                'verbose_name': 'StockInfo',
40
+                'verbose_name_plural': 'StockInfo',
41
+            },
42
+        ),
43
+    ]

+ 20 - 0
stock/migrations/0002_stockinfo_vendorproductname.py

@@ -0,0 +1,20 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.20 on 2019-03-03 21:48
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations, models
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        ('stock', '0001_initial'),
12
+    ]
13
+
14
+    operations = [
15
+        migrations.AddField(
16
+            model_name='stockinfo',
17
+            name='vendorProductName',
18
+            field=models.CharField(blank=True, help_text='\u4f9b\u5e94\u5546\u5546\u54c1\u540d\u79f0', max_length=32, null=True, verbose_name='vendorProductName'),
19
+        ),
20
+    ]

+ 20 - 0
stock/migrations/0003_auto_20190304_0549.py

@@ -0,0 +1,20 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.20 on 2019-03-03 21:49
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations, models
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        ('stock', '0002_stockinfo_vendorproductname'),
12
+    ]
13
+
14
+    operations = [
15
+        migrations.AlterField(
16
+            model_name='stockinfo',
17
+            name='vendorProductName',
18
+            field=models.CharField(blank=True, help_text='\u4f9b\u5e94\u5546\u5546\u54c1\u540d\u79f0', max_length=255, null=True, verbose_name='vendorProductName'),
19
+        ),
20
+    ]

+ 0 - 0
stock/migrations/__init__.py


+ 35 - 0
stock/models.py

@@ -0,0 +1,35 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.db import models
4
+from django.utils.translation import ugettext_lazy as _
5
+from django_models_ext import BaseModelMixin
6
+from shortuuidfield import ShortUUIDField
7
+
8
+
9
+class StockInfo(BaseModelMixin):
10
+    stock_id = ShortUUIDField(_(u'stock_id'), max_length=32, blank=True, null=True, help_text=u'Stock唯一标识', db_index=True)
11
+
12
+    vendorCode = models.CharField(_(u'vendorCode'), max_length=8, blank=True, null=True, help_text=u'供应商简码')
13
+    vendorName = models.CharField(_(u'vendorName'), max_length=32, blank=True, null=True, help_text=u'供应商名称')
14
+    vendorProductId = models.CharField(_(u'vendorProductId'), max_length=32, blank=True, null=True, help_text=u'供应商商品ID', db_index=True)
15
+    vendorProductName = models.CharField(_(u'vendorProductName'), max_length=255, blank=True, null=True, help_text=u'供应商商品名称')
16
+
17
+    storeId = models.CharField(_(u'storeId'), max_length=8, blank=True, null=True, help_text=u'供应商仓库ID')
18
+    storeName = models.CharField(_(u'storeName'), max_length=32, blank=True, null=True, help_text=u'供应商仓库名称')
19
+    # 分仓库存数量=库存总量,预计库存数量=预计库存总量
20
+    quantity = models.IntegerField(_(u'quantity'), default=0, help_text=u'分仓库存数量')
21
+    estimateQuantity = models.IntegerField(_(u'estimateQuantity'), default=0, help_text=u'预计库存数量')
22
+
23
+    # Tamron 填写
24
+    inventoryDate = models.DateTimeField(_(u'inventoryDate'), blank=True, null=True, help_text=_(u'库存日期'))
25
+    totalQuantity = models.IntegerField(_(u'totalQuantity'), default=0, help_text=u'库存总量')
26
+    estimateDate = models.DateTimeField(_(u'estimateDate'), blank=True, null=True, help_text=_(u'预计库存日期'))
27
+    totalEstimateQuantity = models.IntegerField(_(u'totalEstimateQuantity'), default=0, help_text=u'预计库存总量')
28
+    costPrice = models.IntegerField(_(u'costPrice'), default=0, help_text=u'进价')
29
+
30
+    class Meta:
31
+        verbose_name = _(u'StockInfo')
32
+        verbose_name_plural = _(u'StockInfo')
33
+
34
+    def __unicode__(self):
35
+        return u'{0.pk}'.format(self)

+ 7 - 0
stock/tests.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.test import TestCase
5
+
6
+
7
+# Create your tests here.

+ 7 - 0
stock/views.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.shortcuts import render
5
+
6
+
7
+# Create your views here.

+ 80 - 0
utils/stock_utils.py

@@ -0,0 +1,80 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import json
4
+
5
+from django.conf import settings
6
+from TimeConvert import TimeConvert as tc
7
+
8
+import jd
9
+from jd.api.rest.EdiInventorySendRequest import EdiInventorySendRequest
10
+from jd.api.rest.VcAplsStockBatchGetProdStockInfoRequest import VcAplsStockBatchGetProdStockInfoRequest
11
+from jd.api.rest.VcItemProductsFindRequest import VcItemProductsFindRequest
12
+from stock.models import StockInfo
13
+
14
+
15
+JOS = settings.JOS['TAMRON']
16
+
17
+
18
+def refresh_stock_info():
19
+    jd.setDefaultAppInfo(JOS['appkey'], JOS['secret'])
20
+
21
+    a = VcItemProductsFindRequest()
22
+    a.brand_id = 16795
23
+    a.category_id = 834
24
+
25
+    try:
26
+        f = a.getResponse(JOS['accessToken'])
27
+        print(json.dumps(f, ensure_ascii=False))
28
+    except Exception, e:
29
+        print(e)
30
+
31
+    products = f['jingdong_vc_item_products_find_responce']['jos_result_dto']['result']
32
+    print products
33
+
34
+    ware_ids = [int(p['ware_id']) for p in products]
35
+    print ware_ids
36
+
37
+    a = VcAplsStockBatchGetProdStockInfoRequest()
38
+    a.vendorCode = JOS['vendorCode']
39
+    a.skuList = list(set(ware_ids) - set(settings.JOS_SKU_EXCLUDE))
40
+
41
+    try:
42
+        f = a.getResponse(JOS['accessToken'])
43
+        print(json.dumps(f, ensure_ascii=False))
44
+    except Exception, e:
45
+        print(e)
46
+
47
+    stocks = f['jingdong_vc_apls_stock_batchGetProdStockInfo_responce']['batchGetProdStockInfoResponse']['stockList']
48
+    for stock in stocks:
49
+        print stock['sku']
50
+        s, _ = StockInfo.objects.get_or_create(vendorProductId=stock['sku'])
51
+        s.vendorProductName = stock['wname']
52
+        s.vendorCode = JOS['vendorCode']
53
+        s.vendorName = JOS['vendorName']
54
+        s.storeId = JOS['storeId']
55
+        s.storeName = JOS['storeName']
56
+        s.save()
57
+
58
+
59
+def update_stock_info(stock):
60
+    jd.setDefaultAppInfo(JOS['appkey'], JOS['secret'])
61
+
62
+    a = EdiInventorySendRequest()
63
+    a.vendorCode = stock.vendorCode
64
+    a.vendorName = stock.vendorName
65
+    a.vendorProductId = stock.vendorProductId
66
+    a.inventoryDate = tc.local_string(tc.to_local_datetime(stock.inventoryDate))
67
+    a.totalQuantity = stock.totalQuantity
68
+    a.estimateDate = tc.local_string(tc.to_local_datetime(stock.estimateDate))
69
+    a.totalEstimateQuantity = stock.totalEstimateQuantity
70
+    a.costPrice = stock.costPrice
71
+    a.storeId = stock.storeId
72
+    a.storeName = stock.storeName
73
+    a.quantity = stock.totalQuantity
74
+    a.estimateQuantity = stock.totalEstimateQuantity
75
+
76
+    try:
77
+        f = a.getResponse(JOS['accessToken'])
78
+        print(json.dumps(f, ensure_ascii=False))
79
+    except Exception, e:
80
+        print(e)